﻿using System;
using System.Collections.Generic;
using System.Windows.Input;
using Socium.Domain.Collections;
using Socium.Domain.Persons;
using Socium.Presentation;

namespace Socium.Persons {
	class PersonViewModel : FormViewModel<Person> {
		#region Constructors

		public PersonViewModel(Person person) : base(person) {
			InitializeGenerateFullNameCommand();

			
		}

		public PersonViewModel() {
			InitializeGenerateFullNameCommand();
		}

		#endregion

		#region GivenName

		string _given_name;

		public string GivenName {
			get { return _given_name; }
			set {
				using (BeginNameChanging()) {
					_given_name = value;
					OnPropertyChanged("GivenName");
				}
			}
		}

		#endregion

		#region Patronymic

		string _patronymic;

		public string Patronymic {
			get { return _patronymic; }
			set {
				using (BeginNameChanging()) {
					_patronymic = value;
					OnPropertyChanged("Patronymic");
				}
			}
		}

		#endregion

		#region FamilyName

		string _family_name;

		public string FamilyName {
			get { return _family_name; }
			set {
				using (BeginNameChanging()) {
					_family_name = value;
					OnPropertyChanged("FamilyName");
				}
			}
		}

		#endregion

		#region FullName

		string _full_name;

		public string FullName {
			get { return _full_name; }
			set {
				_full_name = value;
				OnPropertyChanged("FullName");
			}
		}

		bool CanGenerateFullName() {
			if (string.IsNullOrEmpty(_given_name)) {
				return false;
			}

			if (string.IsNullOrEmpty(_family_name)) {
				return false;
			}

			return true;
		}

		string GenerateFullName() {
			if (!CanGenerateFullName()) {
				return null;
			}

			var format = string.IsNullOrEmpty(_patronymic) ? "{2} {0}" : "{2} {0} {1}";
			return string.Format(format, _given_name, _patronymic, _family_name);
		}

		NameUpdater BeginNameChanging() {
			return new NameUpdater(this);
		}

		sealed class NameUpdater : IDisposable {
			readonly PersonViewModel _view_model;
			readonly bool _need_update;

			public NameUpdater(PersonViewModel view_model) {
				_view_model = view_model;
				_need_update = (view_model._full_name == _view_model.GenerateFullName());
			}

			public void Dispose() {
				if (_need_update) {
					_view_model.FullName = _view_model.GenerateFullName();
				}
			}
		}

		#endregion

		#region Gender

		GenderOption _gender;

		public GenderOption Gender {
			get { return _gender; }
			set {
				_gender = value;
				OnPropertyChanged("Gender");
			}
		}

		static readonly IEnumerable<GenderOption> _gender_options = CreateGenderOptions();

		static IEnumerable<GenderOption> CreateGenderOptions() {
			return new[] {
				new GenderOption("Male", Domain.Persons.Gender.Male),
				new GenderOption("Female", Domain.Persons.Gender.Female)
			};
		}

		public IEnumerable<GenderOption> GenderOptions {
			get { return _gender_options; }
		}

		#endregion

		#region GenerateFullNameCommand

		public ICommand GenerateFullNameCommand { get; private set; }

		void InitializeGenerateFullNameCommand() {
			GenerateFullNameCommand = new Command(() => FullName = GenerateFullName(), CanGenerateFullName);
		}

		#endregion

		protected override Person CreateModel() {
			return new Person();
		}

		protected override void Update(Person model) {
			GivenName = model.GivenName;
			Patronymic = model.Patronymic;
			FamilyName = model.FamilyName;
			FullName = model.FullName;
			Gender = _gender_options.Find(option => option.Value == model.Gender, null);
		}

		public override bool CanSave() {
			if (string.IsNullOrEmpty(_given_name)) {
				return false;
			}

			if (string.IsNullOrEmpty(_family_name)) {
				return false;
			}

			if (string.IsNullOrEmpty(_full_name)) {
				return false;
			}

			if (_gender == null) {
				return false;
			}

			return true;
		}

		protected override void Save(Person model) {
			model.GivenName = _given_name;
			model.Patronymic = _patronymic;
			model.FamilyName = _family_name;
			model.FullName = _full_name;
			model.Gender = _gender.Value;
		}

		protected override string GetDisplayName(Person model) {
			return model.ToString();
		}

		protected override string GetDefaultDisplayName() {
			return "New person";
		}
	}
}
